-------------------------------------------------------------------------------
--	 File name: init.lua
--		Author: Sploder
-- 		  Date: 03/29/2010
-- Description: This file contains the main body of code used by Cirno's basic
--					weapon.
--
-------------------------------------------------------------------------------

AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")

include("shared.lua")

SWEP.Weight = 5
SWEP.AutoSwitchTo = true
SWEP.AutoSwitchFrom = true

-- Basic attack variables:
SWEP.shotSpeed	= 600		-- The speed at which the projectiles travel.

SWEP.cooldown	= 0.20		-- This is how long the between each shot can be fired.
SWEP.shoottime	= 0			-- This is the next time a shot can be fired. If a shot can be fired, this will be zero.

SWEP.maxShots	= 100		-- The number of shots in a "clip."

SWEP.chargeTime	= 0			-- The next time a shot can be recharged.
SWEP.recharge	= 0.08		-- The amount of time it takes to recharge one shot in the "clip."

SWEP.spreadang	= 5			-- The spread of the shots.

SWEP.jumpForce	= 20		-- The force applied to the player when he shoots in the air.

SWEP.pPerShot	= 0.05		-- The amount of power the player gets when a shot is fired.
SWEP.pPerHit	= 0.10		-- The amount of power the player gets when a shot hits.
SWEP.pPerKill	= 5			-- The amount of power the player gets when he scores a kill.

-- Spellcard variables:
SWEP.cardActive = 0			-- Keeps track of which spellcard is active. (0 = no spellcard active)

SWEP.scTimer	= 40		-- The amount of time a spellcard is active.
SWEP.scTimeout	= 0			-- The last time a timeout sound was played.
SWEP.scKills	= 0			-- The number of kills achieved during a spellcard.

SWEP.sc1shots		= 0		-- The number of shots we've fired in one burst.
SWEP.sc1shottime	= 0.50	-- The amount of time a burst takes to fire.
SWEP.sc1cooldown	= 0.50	-- The amount of time between each burst.
SWEP.sc1spreadang	= 60	-- The spread of the yellow shots.

SWEP.sc2cooldown	= 0.70	-- The amount of time between each burst.
SWEP.sc2shotsmax	= 7		-- The number of shots in a line.

SWEP.sc3shots		= 0		-- The number of shots we've fired in one burst.
SWEP.sc3shottime	= 0.50	-- The amount of time a burst takes to fire.
SWEP.sc3cooldown	= 2.00	-- The amount of time between each burst.
SWEP.sc3spreadang	= 30	-- The spread of the snow shots.
SWEP.sc3charge		= 1.00	-- The amount of time it takes to charge up to freeze you bullets.
SWEP.sc3pressed		= 0		-- The last time at which the player pressed ATTACK2

-------------------------------------------------------------------------------
--	  Function: SWEP:Initialize()
-- Description: This function initializes the weapon.
-------------------------------------------------------------------------------
function SWEP:Initialize()
	self:SetNetworkedFloat("spiritPower", 0)		-- The amount of spirit power the player has.
	self:SetNetworkedInt("spellcardTimer", 0)		-- The time at which the spellcard runs out.
	self:SetNWInt("scactive", false)				-- Tells the client-side which spellcard is active.
	
	self:SetNWInt("shotsLeft", self.maxShots)		-- Set shotsLeft				
	
	math.randomseed(os.time())						-- Seed random.
	
	self:SetMaterial("models/danmaku/sakuya/rKnife2");
	
	self:SetWeaponHoldType("melee")
	
	self:SetNPCMinBurst(5)
	self:SetNPCMaxBurst(15)
	self:SetNPCFireRate(1)
	self:SetNPCMinRest(2)
	self:SetNPCMaxRest(2)
end

-------------------------------------------------------------------------------
--	  Function: SWEP:Holster()
-- Description: This function is called when the user puts the weapon away.
-------------------------------------------------------------------------------
function SWEP:Holster()
	if (self.shoottime < CurTime())
	then
		self.isactive = false
		return true
	else
		-- Draw the weapon?
		return false
	end
	--self:SendWeaponAnim(ACT_VM_HOLSTER);
end

-------------------------------------------------------------------------------
--	  Function: SWEP:Equip( NewOwner )
-- Description: This function is called when the weapon is acquired.
-------------------------------------------------------------------------------
function SWEP:Equip( NewOwner )
	-- It the player has any other weapons, remove them.
end

-------------------------------------------------------------------------------
--	  Function: SWEP:PrimaryAttack()
-- Description: This function is called when the weapon's owner presses attack.
-------------------------------------------------------------------------------
function SWEP:PrimaryAttack()
	-- All shooting-related stuff is now in SWEP:Think.
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SecondaryAttack()
-- Description: This function is called when the weapon's owner presses attack2
-------------------------------------------------------------------------------
function SWEP:SecondaryAttack()
	-- Just to insure it doesn't make that clicking noise.
end

-------------------------------------------------------------------------------
--	  Function: SWEP:Shoot()
-- Description: This function is called to create and fire icicles.
-------------------------------------------------------------------------------
function SWEP:Shoot()
	-- Make noise
	self.Owner:EmitSound("cirno/iceThrow01.wav", 50, 100)
	
	-- Set up the projectile.
	local proj = ents.Create("sent_proj_cirnoice01")
	proj.Owner = self.Owner
	
	-- Place the projectile at the shoot position.
	proj:SetPos(self.Owner:GetShootPos() - Vector(0, 0, 8))
	
	-- Calculate the angle at which to shoot the projectile.
	local aimvector = self.Owner:GetAimVector()
	local pitch, roll, yaw
	pitch = math.random() * self.spreadang - self.spreadang / 2
	roll = math.random() * self.spreadang - self.spreadang / 2
	yaw = math.random() * self.spreadang - self.spreadang / 2
	aimvector:Rotate(Angle(pitch, roll, yaw))
	aimvector:Normalize()
	proj:SetAngles(aimvector:Angle() + Angle(-90,00,00))
	
	-- Spawn the projectile.
	proj:Spawn()
	
	-- Set some physics properties.
	proj:GetPhysicsObject():Wake()
	proj:GetPhysicsObject():EnableDrag(false)
	proj:GetPhysicsObject():EnableGravity(false)
	proj:GetPhysicsObject():SetVelocity(aimvector * self.shotSpeed)
	proj:GetPhysicsObject():SetBuoyancyRatio(0)
		
	proj.pPerHit = self.pPerHit
	proj.pPerKill = self.pPerKill
end

-------------------------------------------------------------------------------
--	  Function: SWEP:ShootWave( curve, direction )
-- Description: This function is called to fire icicles for Icicle Fall.
--		 Input: curve - A number determining the rate at which the shots curve.
--				direction - The offset of the left bullet from straight ahead: Positive = right, negative = left
-------------------------------------------------------------------------------
function SWEP:ShootWave( curve, direction )
	-- Make noise
	self.Owner:EmitSound("cirno/iceThrow01.wav", 50, 100)
	
	-- Create two projectiles, and send them off!
	for i = 0, 1, 1
	do
		local proj = ents.Create("sent_proj_cirnoice01")
		proj.Owner = self.Owner
		
		proj:SetPos(self.Owner:GetShootPos() - Vector(0, 0, 8))-- + (self.Owner:GetRight() * (i * 128 - 64)))
		
		local aimvector = self.Owner:GetAimVector()
		aimvector:Rotate(Angle(0, -115 * (i * 2 - 1), 0))
		proj:SetAngles(aimvector:Angle() + Angle(-90,00,00))
		
		proj:Spawn()
		
		proj:GetPhysicsObject():Wake()
		proj:GetPhysicsObject():EnableDrag(false)
		proj:GetPhysicsObject():EnableGravity(false)
		proj:GetPhysicsObject():SetVelocity(aimvector * self.shotSpeed)
		proj:GetPhysicsObject():SetBuoyancyRatio(0)
		
		proj.timer2 = CurTime() + 0.10
		proj.newDir = direction * (i * 2 - 1)
		
		proj.curve = -(i * curve - curve / 2)	
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SC1ShootSnow ( number )
-- Description: This function is called to shoot snow shots for Icicle Fall.
--		 Input: number - The number of shots to fire.
-------------------------------------------------------------------------------
function SWEP:SC1ShootSnow ( number )
	-- Make noise?
	
	for i = 0, (number - 1), 1
	do
		-- Create a projectile.
		local proj = ents.Create("sent_proj_cirnoice02")
		proj.Owner = self.Owner
		
		proj:SetPos(self.Owner:GetShootPos() - Vector(0, 0, 8))
		
		local offsetang = (self.sc1spreadang / 2) - ((i / (number - 1)) * self.sc1spreadang)
		local aimvector = self.Owner:GetAimVector()
		aimvector:Rotate(Angle(0, offsetang, 0))
		
		proj:Spawn()
		
		proj:GetPhysicsObject():Wake()
		proj:GetPhysicsObject():EnableDrag(false)
		proj:GetPhysicsObject():EnableGravity(false)
		proj:GetPhysicsObject():SetVelocity(aimvector * (self.shotSpeed / 2))
		proj:GetPhysicsObject():SetBuoyancyRatio(0)
		
		proj:SetColor(255,249,199,255)
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SC2ShootColumns ( direction )
-- Description: This function is called to fire a line of ice columns in the
--				specified direction (relative to the player).
-------------------------------------------------------------------------------
function SWEP:SC2ShootColumns ( direction )
	local aimvector = self.Owner:GetForward()
	aimvector = Vector(aimvector.x, aimvector.y, 0)
	aimvector:Normalize()
	aimvector:Rotate(Angle(0,direction,0))

	-- Create a line of ice columns.
	for i = 1, self.sc2shotsmax, 1
	do
		local proj = ents.Create("sent_proj_cirnoice03")
		proj.Owner = self.Owner
		
		proj:SetPos(self.Owner:GetPos() + aimvector * i * 50)--+ Vector(0,0, 16))
		proj:SetAngles(Angle(-90, 0, 0))
		
		proj:Spawn()
		
		proj:GetPhysicsObject():Wake()
		proj:GetPhysicsObject():EnableDrag(false)
		proj:GetPhysicsObject():EnableGravity(false)
		proj:GetPhysicsObject():SetVelocity(Vector(0,0,1) * 200)
		proj:GetPhysicsObject():SetBuoyancyRatio(0)
		
		proj.timer2 = CurTime() + 0.25
		proj.strength = 1000
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SC3Shoot ()
-- Description: This function is called to fire a snow shot...
-------------------------------------------------------------------------------
function SWEP:SC3Shoot()
	-- Make noise
	self.Owner:EmitSound("cirno/iceThrow01.wav", 50, 100)
	
	-- Set up the projectile.
	local proj = ents.Create("sent_proj_cirnoice02")
	proj.Owner = self.Owner
	
	-- Place the projectile at the shoot position.
	proj:SetPos(self.Owner:GetShootPos() - Vector(0, 0, 8))
	
	-- Calculate the angle at which to shoot the projectile.
	local aimvector = self.Owner:GetAimVector()
	local pitch, roll, yaw
	pitch = math.random() * self.sc3spreadang - self.sc3spreadang / 2
	roll = math.random() * self.sc3spreadang - self.sc3spreadang / 2
	yaw = math.random() * self.sc3spreadang - self.sc3spreadang / 2
	aimvector:Rotate(Angle(pitch, roll, yaw))
	aimvector:Normalize()
	proj:SetAngles(aimvector:Angle() + Angle(-90,00,00))
	
	-- Spawn the projectile.
	proj:Spawn()
	
	-- Set some physics properties.
	proj:GetPhysicsObject():Wake()
	proj:GetPhysicsObject():EnableDrag(false)
	proj:GetPhysicsObject():EnableGravity(false)
	proj:GetPhysicsObject():SetVelocity(aimvector * (self.shotSpeed / 2))
	proj:GetPhysicsObject():SetBuoyancyRatio(0)
	
	local color = Color(255,249,199,255)
	local randomnumber = math.random(0, 3)
	if (randomnumber == 1)
	then
		color = Color (184, 255, 159, 255)
	elseif (randomnumber == 2)
	then
		color = Color (159, 248, 255, 255)
	elseif (randomnumber == 3)
	then
		color = Color (238, 159, 255, 255)
	end
	
	proj:SetColor(color.r, color.g, color.b, 255)
end

-------------------------------------------------------------------------------
--	  Function: SWEP:AddPower( number )
-- Description: This function adds the given number to the spirit power.
-------------------------------------------------------------------------------
function SWEP:AddPower( number )
	-- If a spellcard (other than 3) is active, return early.
	if (self.cardActive == 1 || self.cardActive == 2)
	then
		return
	end

	-- Otherwise, add the amount of power to the meter.
	local pow = self:GetNetworkedFloat("spiritPower")
	pow = pow + number
	if (pow < 0) then
		pow = 0
	end
	if (pow > 100) then
		pow = 100
	end
	self:SetNetworkedFloat("spiritPower", pow)
end

-------------------------------------------------------------------------------
--	  Function: SWEP:Think()
-- Description: This function is called every step.
-------------------------------------------------------------------------------
function SWEP:Think()
	-- If a spellcard is active, check the timer.
	if (self.cardActive != 0)
	then
		local timer = self:GetNetworkedInt("spellcardTimer")
		local timeleft = math.Round(timer - CurTime())
		-- If the timer is getting close to expiring, play a sound for each second.
		if (timeleft < 11 && timeleft >= 1)
		then
			-- If timeout is 0, play a sound and record the time it was played.
			if (self.scTimeout == 0)
			then
				self:EmitSound("common/timeout.wav", 100, 100)
				self.scTimeout = CurTime()
			-- If timeout isn't 0, and we've passed the time recorded plus 1 second, reset it.
			elseif (CurTime() >= self.scTimeout + 1)
			then
				self.scTimeout = 0
			end
		end
		
		-- If the timer has expired, end the spellcard.
		if (CurTime() > timer)
		then
			-- If the player has not scored any kills, kill the player.
			if (self.Owner:Frags() - self.scKills <= 0)
			then
				self.Owner:Kill()
			-- Otherwise, just deactivate the spellcard.
			else
				-- If the spellcard was number 3, clear the spirit bar again.
				if (self.cardActive == 3)
				then
					self:AddPower( -100 )
				end
				--self:SetNWInt("scactive", 0)
				
				self.shoottime = 0
				
				self.sc1shots = 0
				self.sc3shots = 0
				self.sc3pressed = 0
				self:SetNWInt("shotsLeft", self.maxShots)
				self:SetNWInt("scactive", 0)
				
				-- Deactivate the spellcard.
				self.cardActive = 0
			end
			
		end
	end
	
	-- If a card is inactive, use the normal attack.
	if (self.cardActive == 0)
	then
		-- Use the basic attack.
		self:BasicAttack()

	-- However, if the spellcard is active, use a different attack.
	elseif (self.cardActive == 1)
	then
		-- Use the first spellcard attack.
		self:SpellCard1()

	elseif (self.cardActive == 2)
	then
		-- Use the second spellcard attack.
		self:SpellCard2()
	elseif (self.cardActive == 3)
	then
		-- Use the third spellcard attack.
		self:SpellCard3()	
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:BasicAttack()
-- Description: This function is called to handle the basic primary attack.
-------------------------------------------------------------------------------
function SWEP:BasicAttack()
	-- If we can shoot, do so.
	if (self.shoottime == 0)
	then
		-- If the player is holding ATTACK, fire a shot.
		if (self.Owner:KeyDown(IN_ATTACK))
		then
			-- Retrieve shotsLeft.
			local shotsLeft	= self:GetNWInt("shotsLeft");
		
			-- If we still have some shots left.
			if (shotsLeft > 0)
			then
				-- Fire a shot.
				self:Shoot()
				-- Add some spirit power.
				self:AddPower(self.pPerShot)
				-- Push the player back a bit, if he's in the air.
				if (!self.Owner:OnGround())
				then
					self.Owner:SetVelocity(self.Owner:GetForward() * -self.jumpForce)
				end
				-- Decrement shotsLeft.
				shotsLeft = shotsLeft - 1
			end
			
			-- Set shotsLeft new value.
			self:SetNWInt("shotsLeft", shotsLeft)
		end
	-- If we can't shoot, but the shoottime has been passed, reset the shoottime (so we can shoot again).
	elseif (self.shoottime < CurTime())
	then
		self.shoottime = 0
	end
	
	-- If we can recharge a shot, do so.
	if (self.chargeTime == 0)
	then
		-- If the player isn't holding ATTACK, recharge.
		if (!self.Owner:KeyDown(IN_ATTACK))
		then
			-- Retrieve shotsLeft.
			local shotsLeft	= self:GetNWInt("shotsLeft");
			
			-- If shotsLeft is less than maxShots, increment shotsLeft.
			if (shotsLeft < self.maxShots)
			then			
				shotsLeft = shotsLeft + 1
				-- Also, set the next chargeTime.
				self.chargeTime = self.recharge
			end
			
			-- Set shotsLeft new value.
			self:SetNWInt("shotsLeft", shotsLeft)
		end
	-- If we can't recharge, but the chargeTime has been passed, reset chargeTime.
	elseif (self.chargeTime < CurTime())
	then
		self.chargeTime = 0
	end	

	-- Check again if we can still shoot.
	if (self.shoottime == 0)
	then
		-- If the player presses ATTACK2 (and shoottime and pressed are still 0), activate a spellcard.
		if (self.Owner:KeyPressed(IN_ATTACK2))
		then
			local power = self:GetNetworkedFloat("spiritPower")
			local alertMessage = ""
			-- If the player has filled only the first bar, use spellcard number 1.
			if (power >= 33 && power < 66)
			then
				self:SetNWInt("scactive", 1)
				self:AddPower ( -power )
				self.cardActive = 1
				alertMessage = "\"Icicle Fall\""
			-- If the player has filled the first two bars, use spellcard number 2.
			elseif (power >= 66 && power < 100)
			then
				self:SetNWInt("scactive", 2)
				self:AddPower ( -power )
				self.cardActive = 2
				alertMessage = "\"Frost Columns\""
			-- If the player has filled all three bars, use spellcard number 3.
			elseif (power >= 100)
			then
				self:SetNWInt("scactive", 3)
				self:AddPower ( -power )
				self.cardActive = 3
				alertMessage = "\"Perfect Freeze\""
			end
			
			-- If we activated a spellcard, notify all players, including the user himself.
			if (self.cardActive != 0)
			then
				self.shoottime = 0
				self.Owner:EmitSound("common/spellcardBig.wav", 100, 100)
				
				-- Make a spellcard use effect.
				local edata = EffectData()
				edata:SetStart(self.Owner:GetShootPos())
				edata:SetOrigin(self.Owner:GetShootPos())
				edata:SetScale(1)
				util.Effect("sprite_spellcardUse", edata)
				
				-- Alert the user that he has activated a spellcard.
				self.Owner:PrintMessage(HUD_PRINTCENTER, "Spellcard activated: " .. alertMessage)
				-- Alert the other players that a spellcard has been activated.
				for i, v in pairs (player.GetAll())
				do
					-- If this player isn't the one who activated the spellcard, send the message.
					if (v != self.Owner)
					then
						v:PrintMessage(HUD_PRINTCENTER, self.Owner:Nick() .. " activated spellcard: " .. alertMessage)
					end
				end
				-- Also, set the spellcard timer.
				self:SetNetworkedInt("spellcardTimer", CurTime() + self.scTimer)
				
				-- And set the kills number
				self.scKills = self.Owner:Frags()		
			end
		end
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SpellCard1()
-- Description: This function is called to handle the first spellcard attack.
-------------------------------------------------------------------------------
function SWEP:SpellCard1()
	-- If we can shoot, do so.
	if (self.shoottime == 0)
	then
		-- If the player is holding ATTACK, fire some shots.
		if (self.Owner:KeyDown(IN_ATTACK))
		then
			-- Easy mode shotsmax
			local sc1ShotsMax	= 0
			local playerHP = self.Owner:Health()
			-- Depending on the amount of health the player has left, determine how many shots can be fired.
			-- Easy mode
			if (playerHP > 50)
			then
				sc1ShotsMax = 6
			-- Normal mode
			elseif (playerHP > 25)
			then
				sc1ShotsMax = 8
			-- Hard mode
			elseif (playerHP > 10)
			then
				sc1ShotsMax = 10
			-- Lunatic
			else
				sc1ShotsMax = 12
			end
			
			-- If we still have shots left, fire!
			if (self.sc1shots < sc1ShotsMax)
			then
				self:ShootWave(30, 50 * (self.sc1shots / sc1ShotsMax) + 90)
				if (sc1ShotsMax > 6 && self.sc1shots % 2 == 0)
				then
					self:SC1ShootSnow(sc1ShotsMax / 2)
				end
				self.sc1shots  = self.sc1shots + 1
				if (self.sc1shots >= sc1ShotsMax)
				then
					self.shoottime = CurTime() + self.sc1cooldown
				else
					self.shoottime = CurTime() + self.sc1shottime * 1 / sc1ShotsMax
				end
			end
		end
	-- If we can't shoot, but the shoottime has been passed, reset the shoottime (so we can shoot again).
	elseif (self.shoottime < CurTime())
	then
		self.shoottime = 0
	end
	
	-- If the player releases ATTACK, reset the wave counter and set shoottime.
	if (self.Owner:KeyReleased(IN_ATTACK))
	then
		self.sc1shots = 0
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SpellCard2()
-- Description: This function is called to handle the second spellcard attack.
-------------------------------------------------------------------------------
function SWEP:SpellCard2()
	-- If we can shoot, do so.
	if (self.shoottime == 0)
	then
		-- If the player presses ATTACK, fire a line of columns.
		if (self.Owner:KeyPressed(IN_ATTACK))
		then
			local playerHP = self.Owner:Health()
			-- Easy mode
				self:SC2ShootColumns(0)
			-- Normal mode
			if (playerHP <= 50)
			then
				self:SC2ShootColumns(180)
			end
			-- Hard mode
			if (playerHP <= 25)
			then
				self:SC2ShootColumns(90)
				self:SC2ShootColumns(270)
			end
			-- Lunatic
			if (playerHP <= 10)
			then
				self:SC2ShootColumns(45)
				self:SC2ShootColumns(135)
				self:SC2ShootColumns(225)
				self:SC2ShootColumns(315)
			end
			
			self.Owner:EmitSound("cirno/iceColumnRise.wav", 50, 100)
			self.shoottime = CurTime() + self.sc2cooldown
		end
	-- If we can't shoot, but the shoottime has been passed, reset the shoottime (so we can shoot again).
	elseif (self.shoottime < CurTime())
	then
		self.shoottime = 0
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:SpellCard3()
-- Description: This function is called to handle the third spellcard attack.
-------------------------------------------------------------------------------
function SWEP:SpellCard3()
	-- If we can shoot, do so.
	if (self.shoottime == 0)
	then
		-- If the player is holding ATTACK, fire a stream of snow shots.
		if (self.Owner:KeyDown(IN_ATTACK))
		then
			-- Easy mode shotsmax
			local sc3ShotsMax	= 0
			local playerHP = self.Owner:Health()
			-- Depending on the amount of health the player has left, determine how many shots can be fired.
			-- Easy mode
			if (playerHP > 50)
			then
				sc3ShotsMax = 50
			-- Normal mode
			elseif (playerHP > 25)
			then
				sc3ShotsMax = 100
			-- Hard mode
			elseif (playerHP > 10)
			then
				sc3ShotsMax = 150
			-- Lunatic
			else
				sc3ShotsMax = 200
			end
			
			-- If we have shots left, fire them.
			if (self.sc3shots < sc3ShotsMax)
			then
				self:SC3Shoot()
				
				-- Push the player back a bit, if he's in the air.
				if (!self.Owner:OnGround())
				then
					self.Owner:SetVelocity(self.Owner:GetForward() * -self.jumpForce)
				end
				
				self.sc3shots  = self.sc3shots + 1
				if (self.sc3shots >= sc3ShotsMax)
				then
					self.shoottime = CurTime() + self.sc3cooldown
				else
					self.shoottime = CurTime() + self.sc3shottime * 1 / (sc3ShotsMax)
				end
			end
			
		end
	-- If we can't shoot, but the shoottime has been passed, reset the shoottime (so we can shoot again).
	elseif (self.shoottime < CurTime())
	then
		self.shoottime = 0
	end
	
	-- If the player releases ATTACK, reset the wave counter.
	if (self.Owner:KeyReleased(IN_ATTACK))
	then
		self.sc3shots = 0
	end
	
	-- If the player presses ATTACK2, freeze his bullets and send them in random directions.
	-- Record the time at which the player presses ATTACK2.
	if (self.Owner:KeyPressed(IN_ATTACK2) && !self.Owner:KeyPressed(IN_ATTACK))
	then
		self.sc3pressed = CurTime()
	end
	
	-- If the player has pressed ATTACK2, see if we can "shoot" yet.
	if (self.sc3pressed != 0)
	then
		-- Find out if we're fully charged.
		local fullycharged = (CurTime() > self.sc3pressed + self.sc3charge)
		
		-- If the player releases attack2, or we're fully charged, do stuff.
		if (self.Owner:KeyReleased(IN_ATTACK2) || fullycharged)
		then
			-- If we had full charge, freeze time for a short time.
			if (fullycharged)
			then
				self.Owner:EmitSound("sakuya/timeStop.wav", 100, 100)
				-- Freeze time!
				self:PerfectFreeze()
				
				-- Begin cooldown cycle.
				self.shoottime = CurTime() + self.cooldown
			-- If we weren't charged, just cost some cooldown.
			else
				-- Begin cooldown cycle.
				self.shoottime = CurTime() + self.sc3cooldown / 2
			end
			-- Reset the pressed thing to zero.
			self.sc3pressed = 0
		end
	end
	
	-- If the player is holding attack2, set the spirit power to correspond with the amount of charge.
	if (self.sc3pressed != 0)
	then
		self:SetNWFloat("spiritPower", 100 * ((CurTime() - self.sc3pressed) / self.sc3charge))
	-- Otherwise, set the spirit power to 0.
	else
		self:SetNWFloat("spiritPower", 0)
	end
end

-------------------------------------------------------------------------------
--	  Function: SWEP:PerfectFreeze()
-- Description: Freezes all of the snow shots belonging to this player, then
--				sends them in random directions.
-------------------------------------------------------------------------------
function SWEP:PerfectFreeze()
	-- Loop through all entities, and freeze the player's snow bullets.
	for k, v in pairs(ents.GetAll())
	do
		if (v:GetClass() == "sent_proj_cirnoice02" && v.Owner == self.Owner)
		then
			v:GetPhysicsObject():SetVelocity(Vector(0,0,0))
			-- Make a random vector.
			local p = math.random() * 359
			local r = math.random() * 359
			local y = math.random() * 359
			local tvector = Vector(1,0,0)
			tvector:Rotate(Angle(p,r,y))
			v.forceVectorx = tvector.x
			v.forceVectory = tvector.y
			v.forceVectorz = tvector.z
			v.forceStr = 1
			v:SetColor(255,255,255,255)
			
			-- Make freeze noise.
			WorldSound("cirno/freeze.wav", self:GetPos(), 80, 100)
		end
	end
end

-------------------------------------------------------------------------------
--	  Function: Console Command CirnoAddSpirit
-- Description: Adds the spellcard equivalent of the provided number to the
--					spirit power meter.
-------------------------------------------------------------------------------
concommand.Add("CirnoAddSpirit", 
	function (ply, cmd, args)
		-- If the player doesn't have the SWEP or he's not an admin, return early.
		if (!ply:HasWeapon("weapon_cirno") || !ply:IsAdmin())
		then
			return
		end
		
		-- This is the number to add to the spirit power meter.
		local power = 0
		
		-- If the player doesn't provide the argument, just assume full.
		if (!args[1])
		then
			power = 100
		-- Otherwise, muliply the argument by 100 / 3 and store it in power.
		else
			power = tonumber(args[1]) * 34
		end
		
		-- Call add power on the player's swep.
		local wep = ply:GetWeapon("weapon_cirno")
			if (wep && wep:IsValid())
			then
				wep:AddPower(power)
			end
	end
)